
// ~ Package Declaration
// ==================================================

package com.wms.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

import org.apache.commons.lang.StringUtils;


// ~ Comments
// ==================================================

/**
 * AD Verification.
 * 
 * <table border="1" width="80%">
 * <tr>
 * <th>Version</th>
 * <th>Date</th>
 * <th>Role</th>
 * <th>Modified By</th>
 * <th>Details</th>
 * </tr>
 * <tr>
 * <td>%I%</td>
 * <td>2011/12/12</td>
 * <td>SD/PG</td>
 * <td>Evan</td>
 * <td>Created By</td>
 * </tr>
 * </table>
 * <p/>
 * 
 * <pre>
 *	AD Verification. 
 * </pre>
 *
 * @author Evan
 * @version 1.0
 * @since 1.5
 * 
 * SVN:
 * <ol>
 * 	<li>$Id$</li>
 * 	<li>$Rev$</li>
 * </ol>
 *
 */
public class ADVerification {

	// ~ Static Fields
	// ==================================================
	
	public final static String LOGIN_MSG_SUCCESS = "SUCCESS";
	public final static String LOGIN_MSG_FAILED= "FAILED";
	public final static String LOGIN_USER_MISSING= "525";
	
	public final static String PROP_AD_IP = "AD_IP";
	public final static String PROP_AD_PORT = "AD_PORT";
	public final static String PROP_AD_DOMAIN = "AD_Domain";
	
	public final static String PROP_AD_LOGIN_OU = "AD_LOGIN_OU";
	public final static String PROP_AD_USER_OU = "AD_USER_OU";
	public final static String PROP_AD_FC_OU = "AD_FC_OU";
	
	public final static String PROP_AD_USERNAME = "AD_username";
	public final static String PROP_AD_PASSWORD = "AD_password";

	private String ldapCtxFactory = "com.sun.jndi.ldap.LdapCtxFactory";
	
	private final static String PROP_DOC_DIR = "project.properties";

	// ~ Fields
	// ==================================================

	// ~ Constructors
	// ==================================================

	// ~ Methods
	// ==================================================
	
	public String verifyUserLogin(String userName, String password) {
		
		String adIP = getAdIP();
		String adPort = getAdPort();
		String adDomain = getAdDomain();
		String strOus = getAdLoginOU();
		
				
		return this.verifyUser(userName, password, adIP, adPort, adDomain, userName, strOus);
	}
	
	public String verifyUserAddUser(String userName) {
		
		String adIP = getAdIP();
		String adPort = getAdPort();
		String adDomain = getAdDomain();
		String strOus = getAdUserOU();
		
		String adUsername = getAdUsername();
		String adPassword = getAdPassword();
		
		return this.verifyUser(adUsername, adPassword, adIP, adPort, adDomain, userName, strOus);
	}
	
	public String verifyUserFC(String userName) {
		
		String adIP = getAdIP();
		String adPort = getAdPort();
		String adDomain = getAdDomain();
		String strOus = getAdFCOU();
		
		String adUsername = getAdUsername();
		String adPassword = getAdPassword();
		
		return this.verifyUser(adUsername, adPassword, adIP, adPort, adDomain, userName, strOus);
	}
	
	private String verifyUser(String userName, String password, String adIP, String adPort, String adDomain, String checkusername, String strOus) {
    
    String msgCode = "";
    
    String[] resultCodes = {"525", "52e", "530", "531", "532", "533", "701", "773", "775"};
    
    try {
        
        Hashtable<String, String> environmentMap = new Hashtable<String, String>(); 
        
        environmentMap.put(Context.INITIAL_CONTEXT_FACTORY, ldapCtxFactory);
        environmentMap.put(Context.PROVIDER_URL, "ldap://" + adIP + ":" + adPort); 
        environmentMap.put(Context.SECURITY_PRINCIPAL, userName + "@" + adDomain);
        environmentMap.put(Context.SECURITY_CREDENTIALS, password); 
        
        msgCode = LOGIN_MSG_SUCCESS;
        
        String strDC = "DC=" + StringUtils.replace(adDomain, ".", ", DC=");
        
        // LdapContext context
        if (!SearchUserInOU(checkusername, strDC, strOus, new InitialLdapContext(environmentMap, null))) {
        	
            msgCode = LOGIN_USER_MISSING;
        }
    }
    catch (Exception e) {
        
        String exceptionMsg = e.getMessage();
        
        if (StringUtils.indexOfAny(exceptionMsg, resultCodes) >= 0) {
            
            for (String resultCode : resultCodes) {
                
                if (exceptionMsg.indexOf(resultCode) >= 0)   { 
                    
                    msgCode = resultCode;
                    
                    break;
                }
            }
        }
        else {
            
            msgCode = LOGIN_MSG_FAILED;
        }
    }
    
    return msgCode;
	}

	private boolean SearchUserInOU(String username, String strDc, String strOus, LdapContext ctx) {
	
    SearchControls constraints = new SearchControls();
    constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
    String[] attrIDs = { "sAMAccountName","distinguishedName" };
    constraints.setReturningAttributes(attrIDs);
    String[] ous;
    
    if (StringUtils.indexOf(strOus, ";") >= 0) {

        ous = StringUtils.split(strOus, ";");
    } 
    else {
    	
        ous = new String[]{ strOus };
    }
    
    for (String ou : ous) {
    	
        try {
        	
            // First input parameter is search bas, it can be
            // "CN=Users,DC=YourDomain,DC=com"
            // Second Attribute can be sAMAccountName=username
            NamingEnumeration<SearchResult> answer = 
            	ctx.search("OU=" + ou + "," + strDc, "sAMAccountName=" + username, constraints);
            
            if (answer.hasMore()) {
            	
                Attributes attrs = ((SearchResult) answer.next()).getAttributes();
                
                // User is valid
                return (attrs.get("sAMAccountName").get().equals(username));
            }
        } 
        catch (javax.naming.NameNotFoundException nnfe) {

        } 
        catch (Exception ex) {
        	
            return false;
        }
    }
    return false;
	}
	
	public String getAdIP() {
	
		Properties load = load();
		
		return load.getProperty(PROP_AD_IP);
	}

	public String getAdPort() {
	
		Properties load = load();
		
		return load.getProperty(PROP_AD_PORT);
	}
	
	public String getAdDomain() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_DOMAIN);
	}
	
	public String getAdLoginOU() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_LOGIN_OU);
	}
	
	public String getAdUserOU() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_USER_OU);
	}
	
	public String getAdFCOU() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_FC_OU);
	}
	
	public String getAdUsername() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_USERNAME);
	}
	
	public String getAdPassword() {
		
		Properties load = load();
		
		return load.getProperty(PROP_AD_PASSWORD);
	}

	/**
	 * load Properties.
	 *
	 * <pre>
	 * 	load Properties
	 * </pre>
	 *
	 * @return
	 */
	private Properties load() {
		
		Properties properties = new Properties();
		ClassLoader loader = this.getClass().getClassLoader();
		InputStream inStream = loader.getResourceAsStream(PROP_DOC_DIR);
		
		try {
				
			properties.load(inStream);
		} 
		catch (IOException ioe) {
			
			ioe.printStackTrace();
		} 
		finally {
			
			if (inStream != null) {
				
				try {
					
					inStream.close();
				} 
				catch (IOException ioe) {
					
					ioe.printStackTrace();
				}
			}
		}
			
		return properties;
	}
}